package com.daocheng.dc.book.user.biz.service.impl;

import com.daocheng.dc.book.oss.api.FileFeignApi;
import com.daocheng.dc.book.user.biz.constant.RedisKeyConstant;
import com.daocheng.dc.book.user.biz.constant.RoleConstant;
import com.daocheng.dc.book.user.biz.domain.dataobject.RoleDO;
import com.daocheng.dc.book.user.biz.domain.dataobject.UserDO;
import com.daocheng.dc.book.user.biz.domain.dataobject.UserRoleRelDO;
import com.daocheng.dc.book.user.biz.domain.mapper.RoleDOMapper;
import com.daocheng.dc.book.user.biz.domain.mapper.UserDOMapper;
import com.daocheng.dc.book.user.biz.domain.mapper.UserRoleRelDOMapper;
import com.daocheng.dc.book.user.biz.enums.ResponseCodeEnum;
import com.daocheng.dc.book.user.biz.enums.SexEnum;
import com.daocheng.dc.book.user.biz.model.vo.UpdateUserInfoReqVO;
import com.daocheng.dc.book.user.biz.rpc.OssRpcService;
import com.daocheng.dc.book.user.biz.service.UserService;
import com.daocheng.dc.book.user.dto.req.FindByPhoneReqDTO;
import com.daocheng.dc.book.user.dto.req.RegisterUserReqDTO;
import com.daocheng.dc.book.user.dto.req.UpdatePasswordReqDTO;
import com.daocheng.dc.book.user.dto.rsp.FindByPhoneRspDTO;
import com.daocheng.framework.biz.context.holder.LoginUserContextHolder;
import com.daocheng.framework.common.enums.DeletedEnum;
import com.daocheng.framework.common.enums.StatusEnum;
import com.daocheng.framework.common.exception.BizException;
import com.daocheng.framework.common.response.Response;
import com.daocheng.framework.common.utils.JsonUtils;
import com.daocheng.framework.common.utils.ParamUtils;
import com.google.common.base.Preconditions;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.User;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @ClassName UserServiceImpl
 * @author: 稻城
 * @date: 2025/3/26
 * @Version 1.0
 * @description: TODO
 */
@Service
@Slf4j
public class UserServiceImpl implements UserService {
    @Resource
    private UserDOMapper userDOMapper;
    @Resource
    private FileFeignApi fileFeignApi;
    @Resource
    private OssRpcService ossRpcService;
    @Resource
    private UserRoleRelDOMapper userRoleRelDOMapper;
    @Resource
    private RoleDOMapper roleDOMapper;
    @Resource
    private RedisTemplate<String,Object> redisTemplate;

    @Override
    public Response<?> updateUserInfo(UpdateUserInfoReqVO updateUserInfoReqVO) {
        UserDO userDO = new UserDO();
        userDO.setId(LoginUserContextHolder.getUserId());
        boolean needUpdate = false;

        // 头像
        MultipartFile avatarFile = updateUserInfoReqVO.getAvatar();
        System.err.println(avatarFile);
        if (Objects.nonNull(avatarFile)) {
            String avatar = ossRpcService.uploadFile(avatarFile);
            log.info("==> 调用 oss 服务成功，上传头像，url：{}", avatar);
            // 若上传头像失败，则抛出业务异常
            if (StringUtils.isBlank(avatar)) {
                throw new BizException(ResponseCodeEnum.UPLOAD_FILE_FAIL);
            }
            userDO.setAvatar(avatar);
            needUpdate = true;
        }
        //昵称
        if (Objects.nonNull(updateUserInfoReqVO.getNickname())) {
            Preconditions.checkArgument(ParamUtils.checkNickname(updateUserInfoReqVO.getNickname()), ResponseCodeEnum.NICK_NAME_VALID_FAIL.getErrorMessage());
            userDO.setNickname(updateUserInfoReqVO.getNickname());
            needUpdate = true;
        }
        // 稻城书号
        if (Objects.nonNull(updateUserInfoReqVO.getDcBookId())) {
            Preconditions.checkArgument(ParamUtils.checkXiaohashuId(updateUserInfoReqVO.getDcBookId()), ResponseCodeEnum.DC_BOOK_ID_VALID_FAIL.getErrorMessage());
            userDO.setDcBookId(updateUserInfoReqVO.getDcBookId());
            needUpdate = true;
        }
        // 生日
        if (Objects.nonNull(updateUserInfoReqVO.getBirthday())) {
            userDO.setBirthday(updateUserInfoReqVO.getBirthday());
            needUpdate = true;
        }
        // 个人简介
        if (Objects.nonNull(updateUserInfoReqVO.getIntroduction())) {
            Preconditions.checkArgument(ParamUtils.checkLength(updateUserInfoReqVO.getIntroduction(), 100), ResponseCodeEnum.INTRODUCTION_VALID_FAIL.getErrorMessage());
            userDO.setIntroduction(updateUserInfoReqVO.getIntroduction());
            needUpdate = true;
        }
        // 性别
        if (Objects.nonNull(updateUserInfoReqVO.getSex())) {
            Preconditions.checkArgument(SexEnum.isValid(updateUserInfoReqVO.getSex()), ResponseCodeEnum.SEX_VALID_FAIL.getErrorMessage());
            userDO.setSex(updateUserInfoReqVO.getSex());
            needUpdate = true;
        }
        // 背景图片
        MultipartFile backgroundImgFile = updateUserInfoReqVO.getBackgroundImg();
        if (Objects.nonNull(backgroundImgFile)) {
            String backgroundUrl = ossRpcService.uploadFile(backgroundImgFile);
            log.info("==> 调用 oss 服务成功，上传背景图，url：{}", backgroundUrl);
            // 若上传头像失败，则抛出业务异常
            if (StringUtils.isBlank(backgroundUrl)) {
                throw new BizException(ResponseCodeEnum.UPLOAD_FILE_FAIL);
            }
            userDO.setBackgroundImg(backgroundUrl);
            needUpdate = true;
        }
        if (needUpdate) {
            // 更新用户信息
            userDO.setUpdateTime(LocalDateTime.now());
            userDOMapper.updateByPrimaryKeySelective(userDO);
        }
        return Response.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Response<Long> register(RegisterUserReqDTO registerUserReqDTO) {
        String phone = registerUserReqDTO.getPhone();
        //判断手机号是否注册过
        UserDO userDO1 = userDOMapper.selectByPhone(phone);
        if(Objects.nonNull(userDO1)){
            return Response.success(userDO1.getId());
        }
        //获取稻城书全局自增长的id
        Long dcBookId = redisTemplate.opsForValue().increment(RedisKeyConstant.DC_BOOK_ID_GENERATOR_KEY);
        UserDO userDO = UserDO.builder()
                .dcBookId(String.valueOf(dcBookId))
                .nickname("稻城书" + dcBookId)
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .phone(phone)
                .status(StatusEnum.ENABLE.getValue())
                .isDeleted(DeletedEnum.NO.getValue())
                .build();
        //添加入库
        userDOMapper.insert(userDO);
        Long userId = userDO.getId();
        //给用户默认角色
        UserRoleRelDO userRoleRelDO = UserRoleRelDO.builder()
                .userId(userId)
                .roleId(RoleConstant.COMMON_USER_ROLE_ID)
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .isDeleted(DeletedEnum.NO.getValue())
                .build();
        userRoleRelDOMapper.insert(userRoleRelDO);
        RoleDO roleDo = roleDOMapper.selectByPrimaryKey(RoleConstant.COMMON_USER_ROLE_ID);
        //将该用户的角色存入到Redis里
        List<String> roles = new ArrayList<>(1);
        roles.add(roleDo.getRoleKey());
        String userRoleKey = RedisKeyConstant.buildUserRoleKey(userId);
        redisTemplate.opsForValue().set(userRoleKey, JsonUtils.toJsonString(roles));
//        return userId;
        return Response.success(userId);
    }

    @Override
    public Response<FindByPhoneRspDTO> findByPhone(FindByPhoneReqDTO findByPhoneReqDTO) {
        String phone = findByPhoneReqDTO.getPhone();
        UserDO userDO = userDOMapper.selectByPhone(phone);
        if(Objects.isNull(userDO)){
            throw new BizException(ResponseCodeEnum.FOUND_USER_FAIL);
        }
        FindByPhoneRspDTO findByPhoneRspDTO = FindByPhoneRspDTO.builder()
                .id(userDO.getId())
                .password(userDO.getPassword())
                .build();
        return Response.success(findByPhoneRspDTO);
    }

    @Override
    public Response<?> updatePassword(UpdatePasswordReqDTO updatePasswordReqDTO) {
        Long userId = LoginUserContextHolder.getUserId();
        UserDO userDO = UserDO.builder()
                .id(userId)
                .password(updatePasswordReqDTO.getNewPassword())
                .updateTime(LocalDateTime.now())
                .build();
        userDOMapper.updateByPrimaryKey(userDO);
        return Response.success();
    }
}
